Popular Searches
Popular Course Categories
Popular Courses

Using Pressable, Button, and Touchable Components

Using Pressable, Button, and Touchable Components

React Native Components and Core APIs

Using Pressable, Button, and Touchable Components in React Native

Course: React Native Training

Topic: Using Pressable, Button, and Touchable Components

Course Link: React Native Training at JustAcademy

Demo Link: Register for a Course Demo

Website: JustAcademy Official Website


1. Introduction to Touch Interactions in React Native

Touch interactions are an essential part of mobile application development. Users interact with mobile applications by tapping buttons, selecting cards, submitting forms, opening menus, confirming actions, and pressing and holding interface elements.

React Native provides several built-in components for handling touch interactions, including Pressable, Button, TouchableOpacity, TouchableHighlight, and TouchableWithoutFeedback. These components help developers detect user actions and provide feedback when an element is pressed.

Each component has a different purpose. The Button component provides a simple platform-rendered button, Pressable supports flexible styling and detailed press events, and Touchable components provide different types of touch feedback.

Learning Objectives

  • Understand how touch interactions work in React Native.
  • Learn the purpose and usage of Pressable.
  • Create basic buttons using the Button component.
  • Understand TouchableOpacity and TouchableHighlight.
  • Learn when TouchableWithoutFeedback is appropriate.
  • Handle onPress, onPressIn, onPressOut, and onLongPress events.
  • Manage disabled buttons and button states.
  • Build reusable, accessible buttons with custom styling.
  • Implement practical examples and troubleshoot common issues.

2. Understanding Touch Events

A touch event occurs when a user interacts with an element on the screen. For example, when a user taps a Login button, the application can validate the form and navigate to the next screen.

Touch components connect a user's physical interaction with JavaScript functions. These functions are commonly called event handlers or callback functions.

Basic Example

import React from 'react';
import { View, Text, Pressable, Alert } from 'react-native';

export default function App() {
  const handlePress = () => {
    Alert.alert('Success', 'You pressed the button!');
  };

  return (
    <View>
      <Pressable onPress={handlePress}>
        <Text>Press Me</Text>
      </Pressable>
    </View>
  );
}

Explanation

  • Pressable makes the wrapped content respond to touch interactions.
  • onPress specifies the function that runs when the press is recognized.
  • handlePress contains the action performed after the user presses the component.
  • Alert.alert() displays a native alert dialog.
  • Text provides the visible label for the pressable element.

Touch handlers are useful for navigation, form submission, changing application state, selecting list items, and opening or closing interface elements.

3. What Is Pressable?

Pressable is a built-in React Native component that makes its children respond to press interactions. It supports different event callbacks and allows developers to change the appearance of an element depending on whether it is being pressed.

Pressable is a flexible choice for building custom buttons, interactive cards, clickable list items, menu options, and other touch-enabled elements. It is generally a good starting point for new custom interactive components.

Basic Syntax

<Pressable onPress={() => console.log('Pressed')}>
  <Text>Click Here</Text>
</Pressable>

Example: Styled Pressable Button

import React from 'react';
import {
  View,
  Text,
  Pressable,
  StyleSheet,
  Alert
} from 'react-native';

export default function App() {
  return (
    <View style={styles.container}>
      <Pressable
        style={styles.button}
        onPress={() => Alert.alert('Hello', 'Welcome to React Native!')}
      >
        <Text style={styles.buttonText}>Get Started</Text>
      </Pressable>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center'
  },
  button: {
    backgroundColor: '#2563eb',
    paddingVertical: 14,
    paddingHorizontal: 28,
    borderRadius: 8
  },
  buttonText: {
    color: '#ffffff',
    fontSize: 16,
    fontWeight: 'bold'
  }
});

Important Features of Pressable

  • Supports custom styling and layout.
  • Provides callbacks for press interactions.
  • Can change its style based on the pressed state.
  • Supports long-press interactions.
  • Can be disabled when an action is unavailable.
  • Supports accessibility-related properties.
  • Can wrap complex content such as icons, text, and images.

4. Important Pressable Props

Props configure the behavior and appearance of a Pressable component.

Prop Purpose Example
onPress Runs when a press is successfully recognized. onPress={handlePress}
onPressIn Runs when the press interaction begins. onPressIn={handlePressIn}
onPressOut Runs when the press interaction ends. onPressOut={handlePressOut}
onLongPress Runs when the user presses and holds long enough. onLongPress={handleLongPress}
disabled Disables the press interaction. disabled={true}
style Defines the component's visual style. style={styles.button}
hitSlop Expands the area from which a touch can begin. hitSlop={10}
delayLongPress Configures the delay before a long press is recognized. delayLongPress={800}
android_ripple Configures Android ripple feedback where supported. android_ripple={'{ color: "#dddddd" }'}
accessibilityRole Communicates the element's role to accessibility services. accessibilityRole="button"

Always check the documentation for the React Native version used by your project, because supported properties and platform behavior can vary.

5. Understanding onPress

The onPress callback is one of the most commonly used touch event handlers. It runs when the interaction is recognized as a completed press rather than a cancelled gesture.

Example

import React from 'react';
import { View, Text, Pressable, Alert } from 'react-native';

export default function App() {
  const handlePress = () => {
    Alert.alert('Button Pressed');
  };

  return (
    <View>
      <Pressable onPress={handlePress}>
        <Text>Submit</Text>
      </Pressable>
    </View>
  );
}

Common Uses

  • Submitting forms.
  • Opening another screen.
  • Saving user preferences.
  • Adding a product to a cart.
  • Opening a modal or menu.
  • Updating a counter or selection.

Pass a function reference such as onPress={handlePress} rather than calling the function during rendering with onPress={handlePress()}. Calling it immediately may execute the action before the user interacts with the component.

6. Understanding onPressIn and onPressOut

Pressable provides callbacks for the beginning and end of a touch interaction. These events can be useful when implementing custom animations, visual feedback, or interaction tracking.

  • onPressIn: Runs when the press interaction begins.
  • onPressOut: Runs when the press interaction ends.
  • onPress: Runs when the interaction is recognized as a completed press.

Example

import React from 'react';
import { View, Text, Pressable, Alert } from 'react-native';

export default function App() {
  return (
    <View style={{ padding: 30 }}>
      <Pressable
        onPressIn={() => console.log('Press started')}
        onPressOut={() => console.log('Press ended')}
        onPress={() => Alert.alert('Action completed')}
      >
        <Text>Press and Release</Text>
      </Pressable>
    </View>
  );
}

These callbacks may run in sequence as the user interacts with the component. Do not assume that every onPressIn event will result in an onPress event; the gesture can be cancelled.

7. Handling Long Press with Pressable

A long press occurs when a user presses and holds an element for a specified duration. It is useful for contextual menus, item selection, additional options, and certain editing actions.

Example

import React from 'react';
import { View, Text, Pressable, Alert } from 'react-native';

export default function App() {
  return (
    <View style={{ padding: 20 }}>
      <Pressable
        onPress={() => Alert.alert('Tap', 'Short press detected')}
        onLongPress={() => Alert.alert('Long Press', 'You held the button')}
        delayLongPress={700}
      >
        <Text>Tap or Hold This Text</Text>
      </Pressable>
    </View>
  );
}

The delayLongPress property controls the delay before the long-press callback is triggered. Choose a duration that feels natural for the interaction and test it on real devices.

8. Dynamic Styling with Pressable

One of Pressable's useful features is its ability to receive a function for the style prop. The function receives a state object containing information about the current press interaction.

Example

import React from 'react';
import { View, Text, Pressable, StyleSheet } from 'react-native';

export default function App() {
  return (
    <View style={styles.container}>
      <Pressable
        style={({ pressed }) => [
          styles.button,
          pressed && styles.buttonPressed
        ]}
        onPress={() => console.log('Button pressed')}
      >
        {({ pressed }) => (
          <Text style={styles.buttonText}>
            {pressed ? 'Pressing...' : 'Press Me'}
          </Text>
        )}
      </Pressable>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center'
  },
  button: {
    backgroundColor: '#2563eb',
    padding: 16,
    borderRadius: 8
  },
  buttonPressed: {
    backgroundColor: '#1e40af',
    transform: [{ scale: 0.98 }]
  },
  buttonText: {
    color: '#ffffff',
    fontSize: 16,
    fontWeight: 'bold'
  }
});

Explanation

  • The style function receives the current pressed state.
  • The base style is always applied.
  • The pressed style is added only while the component is pressed.
  • The child render function can also display different content according to the pressed state.

Dynamic styling can provide useful feedback without maintaining a separate React state variable for a simple pressed interaction.

9. What Is the Button Component?

The React Native Button component is a built-in component for creating simple buttons. It provides a standard platform-rendered appearance and requires very little code.

Button is useful when you need a basic action such as submitting a form, confirming a choice, or triggering a simple function without building a fully customized button design.

Basic Syntax

import React from 'react';
import { View, Button, Alert } from 'react-native';

export default function App() {
  return (
    <View>
      <Button
        title="Click Me"
        onPress={() => Alert.alert('Hello', 'Button clicked')}
      />
    </View>
  );
}

Important Button Props

Prop Description
title The text displayed on the button.
onPress The function executed when the button is pressed.
color Sets the button's platform-supported color treatment.
disabled Disables the button when set to true.
accessibilityLabel Provides an accessible description of the button.
testID Provides an identifier useful for automated testing.

The Button component has limited styling options compared with Pressable and Touchable components. Its appearance also varies by platform. Use Pressable when you need complete control over layout, icons, typography, borders, and pressed-state styling.

10. Creating Buttons with Different Actions

Multiple Button components can trigger different functions. This pattern is useful for simple action menus, confirmation screens, and basic demonstrations.

import React from 'react';
import { View, Button, Alert, StyleSheet } from 'react-native';

export default function App() {
  const handleSave = () => {
    Alert.alert('Saved', 'Your information has been saved.');
  };

  const handleCancel = () => {
    Alert.alert('Cancelled', 'The operation was cancelled.');
  };

  return (
    <View style={styles.container}>
      <Button title="Save" onPress={handleSave} color="#16a34a" />
      <View style={styles.spacing} />
      <Button title="Cancel" onPress={handleCancel} color="#dc2626" />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    padding: 20
  },
  spacing: {
    height: 12
  }
});

In this example, each button has a separate handler. The color property adjusts the button's color treatment, but exact rendering differs across platforms.

11. Disabling a Button

A disabled button prevents users from triggering an action when it is unavailable. For example, a Submit button may remain disabled until all required form fields are completed.

Button Example

<Button
  title="Submit"
  onPress={handleSubmit}
  disabled={true}
/>

Pressable Example

<Pressable
  onPress={handleSubmit}
  disabled={!isFormValid}
  style={({ pressed }) => [
    styles.button,
    !isFormValid && styles.disabledButton,
    pressed && isFormValid && styles.pressedButton
  ]}
>
  <Text style={styles.buttonText}>Submit</Text>
</Pressable>

For a custom Pressable, the disabled style must be defined in your stylesheet. The disabled prop prevents the press interaction, while the style communicates the disabled state visually.

12. Creating a Reusable Custom Button

A reusable button allows developers to share a consistent design across the application. Instead of repeating the same Pressable markup on every screen, create a component that accepts props such as title, onPress, disabled, and variant.

Reusable Button Component

import React from 'react';
import {
  Text,
  Pressable,
  StyleSheet
} from 'react-native';

export default function CustomButton({
  title,
  onPress,
  disabled = false
}) {
  return (
    <Pressable
      onPress={onPress}
      disabled={disabled}
      accessibilityRole="button"
      accessibilityLabel={title}
      style={({ pressed }) => [
        styles.button,
        disabled && styles.disabled,
        pressed && !disabled && styles.pressed
      ]}
    >
      <Text style={styles.buttonText}>{title}</Text>
    </Pressable>
  );
}

const styles = StyleSheet.create({
  button: {
    backgroundColor: '#2563eb',
    paddingVertical: 14,
    paddingHorizontal: 22,
    borderRadius: 8,
    alignItems: 'center'
  },
  pressed: {
    backgroundColor: '#1d4ed8'
  },
  disabled: {
    backgroundColor: '#9ca3af'
  },
  buttonText: {
    color: '#ffffff',
    fontSize: 16,
    fontWeight: 'bold'
  }
});

Using the Reusable Component

import React from 'react';
import { View, Alert } from 'react-native';
import CustomButton from './CustomButton';

export default function App() {
  return (
    <View style={{ padding: 20 }}>
      <CustomButton
        title="Login"
        onPress={() => Alert.alert('Login', 'Login selected')}
      />
      <CustomButton
        title="Continue"
        disabled={true}
        onPress={() => console.log('Continue')}
      />
    </View>
  );
}

Save the reusable component in a file such as CustomButton.js and import it wherever needed. Reusable components reduce duplication and make design changes easier to maintain.

13. What Are Touchable Components?

Touchable components are built-in React Native components that make child elements respond to touch. They are useful for creating custom buttons and interactive interface elements.

The most commonly used Touchable components include:

  • TouchableOpacity
  • TouchableHighlight
  • TouchableWithoutFeedback
  • TouchableNativeFeedback, which is primarily intended for Android-specific feedback.

For new custom interactions, React Native recommends considering Pressable because it offers flexible feedback and a more extensive set of press-state options. Touchable components remain useful in existing applications and for familiar interaction patterns.

14. Understanding TouchableOpacity

TouchableOpacity is a touchable component that reduces the opacity of its children while the user presses it. This creates a simple visual feedback effect.

It is commonly used for custom buttons, navigation items, image cards, and tappable text.

Basic Example

import React from 'react';
import {
  View,
  Text,
  TouchableOpacity,
  Alert,
  StyleSheet
} from 'react-native';

export default function App() {
  return (
    <View style={styles.container}>
      <TouchableOpacity
        style={styles.button}
        activeOpacity={0.7}
        onPress={() => Alert.alert('Success', 'TouchableOpacity pressed')}
      >
        <Text style={styles.buttonText}>Tap Here</Text>
      </TouchableOpacity>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center'
  },
  button: {
    backgroundColor: '#7c3aed',
    paddingVertical: 14,
    paddingHorizontal: 24,
    borderRadius: 8
  },
  buttonText: {
    color: '#ffffff',
    fontSize: 16,
    fontWeight: 'bold'
  }
});

Understanding activeOpacity

The activeOpacity prop controls the opacity of the wrapped content during the active press. A lower value generally makes the content appear more transparent. The default value is 0.2.

<TouchableOpacity
  activeOpacity={0.5}
  onPress={handlePress}
>
  <Text>Press Me</Text>
</TouchableOpacity>

Common Use Cases

  • Buttons with custom designs.
  • Clickable product images.
  • Navigation links and menu items.
  • Interactive profile cards.
  • Custom list rows.

TouchableOpacity changes opacity to provide feedback. If you want to control several pressed-state styles, such as background color and scale, Pressable is often more flexible.

15. Understanding TouchableHighlight

TouchableHighlight provides touch feedback by showing an underlay color when the user presses the component. This can create a darkening or highlighting effect.

TouchableHighlight requires a single child element. If you want to include multiple elements, wrap them inside a View.

Example

import React from 'react';
import {
  View,
  Text,
  TouchableHighlight,
  Alert,
  StyleSheet
} from 'react-native';

export default function App() {
  return (
    <View style={styles.container}>
      <TouchableHighlight
        style={styles.button}
        underlayColor="#1d4ed8"
        activeOpacity={0.85}
        onPress={() => Alert.alert('Pressed', 'Highlight button pressed')}
      >
        <Text style={styles.buttonText}>Highlight Button</Text>
      </TouchableHighlight>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center'
  },
  button: {
    backgroundColor: '#2563eb',
    padding: 16,
    borderRadius: 8
  },
  buttonText: {
    color: '#ffffff',
    fontWeight: 'bold'
  }
});

Important Props

  • underlayColor: sets the color displayed behind the child during a press.
  • activeOpacity: controls the opacity of the wrapped content during the active press.
  • onPress: specifies the action performed when the press is recognized.
  • onShowUnderlay: runs when the underlay becomes visible.
  • onHideUnderlay: runs when the underlay is hidden.

Choose an underlay color that works with the child element's background. An unsuitable color or transparent styling may create unexpected visual effects.

16. Understanding TouchableWithoutFeedback

TouchableWithoutFeedback detects touch interactions without adding its own visual feedback. It is useful for specific interaction patterns where the interface should respond to a touch without changing its appearance.

It should be used carefully because users generally benefit from visible feedback when an element is interactive. It supports one child, so wrap multiple child elements inside a View.

Example

import React from 'react';
import {
  View,
  Text,
  TouchableWithoutFeedback,
  Alert,
  StyleSheet
} from 'react-native';

export default function App() {
  return (
    <View style={styles.container}>
      <TouchableWithoutFeedback
        onPress={() => Alert.alert('Selected', 'Area tapped')}
      >
        <View style={styles.box}>
          <Text>Tap This Area</Text>
        </View>
      </TouchableWithoutFeedback>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center'
  },
  box: {
    padding: 30,
    backgroundColor: '#eeeeee',
    borderRadius: 8
  }
});

Common Use Cases

  • Detecting touches on a background area.
  • Implementing specific custom touch behavior.
  • Handling touches where visual feedback is provided elsewhere.

For ordinary buttons, prefer a component that provides visible feedback and an appropriate accessibility role.

17. Understanding TouchableNativeFeedback

TouchableNativeFeedback is a React Native component primarily designed for Android-specific native touch feedback, such as ripple effects.

Its use is more platform-specific than Pressable or TouchableOpacity. For cross-platform applications, Pressable with its android_ripple property is often a convenient alternative when Android ripple feedback is desired.

Example Using Pressable Ripple Feedback

import React from 'react';
import {
  View,
  Text,
  Pressable,
  StyleSheet
} from 'react-native';

export default function App() {
  return (
    <View style={styles.container}>
      <Pressable
        android_ripple={{ color: '#bfdbfe' }}
        style={styles.button}
        onPress={() => console.log('Ripple button pressed')}
      >
        <Text style={styles.buttonText}>Android Ripple Button</Text>
      </Pressable>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    padding: 20
  },
  button: {
    backgroundColor: '#2563eb',
    padding: 16,
    borderRadius: 8,
    overflow: 'hidden'
  },
  buttonText: {
    color: '#ffffff',
    fontWeight: 'bold'
  }
});

The ripple effect is platform-specific. Test it on Android and verify how the component looks on iOS, where Android ripple feedback is not displayed in the same way.

18. Comparing Pressable, Button, and Touchable Components

Component Touch Feedback Styling Flexibility Best Use
Pressable Configurable using pressed state, callbacks, and supported platform feedback. High Custom buttons, cards, list items, and complex interactions.
Button Platform-rendered button feedback. Limited Simple actions that need minimal customization.
TouchableOpacity Reduces opacity while pressed. High Custom buttons, links, and tappable content.
TouchableHighlight Shows an underlay color. High Elements that benefit from a highlight effect.
TouchableWithoutFeedback No built-in visual press feedback. High Special cases requiring touch detection without a visual effect.
TouchableNativeFeedback Android-native feedback such as ripples. Platform-specific Existing Android-focused implementations.

Which Component Should You Choose?

  • Choose Pressable when you need a modern, customizable interaction with detailed press-state handling.
  • Choose Button when a simple, platform-rendered action button is sufficient.
  • Choose TouchableOpacity when opacity-based feedback fits your design.
  • Choose TouchableHighlight when a visible underlay effect is desired.
  • Choose TouchableWithoutFeedback only when its lack of built-in feedback is intentional.
  • Choose TouchableNativeFeedback for existing Android-specific implementations where appropriate.

19. Managing Button State with useState

The useState hook allows a component to remember and update values. It is useful for interactive elements such as counters, favorite buttons, selection controls, and toggle actions.

Example: Counter Button

import React, { useState } from 'react';
import {
  View,
  Text,
  Pressable,
  StyleSheet
} from 'react-native';

export default function CounterApp() {
  const [count, setCount] = useState(0);

  return (
    <View style={styles.container}>
      <Text style={styles.count}>Count: {count}</Text>

      <Pressable
        style={styles.button}
        onPress={() => setCount(previous => previous + 1)}
      >
        <Text style={styles.buttonText}>Increase Count</Text>
      </Pressable>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center'
  },
  count: {
    fontSize: 24,
    marginBottom: 20
  },
  button: {
    backgroundColor: '#16a34a',
    padding: 16,
    borderRadius: 8
  },
  buttonText: {
    color: '#ffffff',
    fontWeight: 'bold'
  }
});

Each press updates the count. React then re-renders the component to display the new value. The functional updater form ensures that the new count is calculated from the previous state.

20. Building a Favorite Button

Favorite buttons are commonly used in shopping, travel, and social applications. A user can tap the button to mark or unmark an item as a favorite.

import React, { useState } from 'react';
import {
  View,
  Text,
  Pressable,
  StyleSheet
} from 'react-native';

export default function FavoriteButton() {
  const [favorite, setFavorite] = useState(false);

  return (
    <View style={styles.container}>
      <Pressable
        onPress={() => setFavorite(previous => !previous)}
        accessibilityRole="button"
        accessibilityLabel={
          favorite ? 'Remove from favorites' : 'Add to favorites'
        }
        style={styles.button}
      >
        <Text style={styles.buttonText}>
          {favorite ? '♥ Added to Favorites' : '♡ Add to Favorites'}
        </Text>
      </Pressable>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    padding: 20
  },
  button: {
    alignSelf: 'flex-start',
    padding: 14,
    backgroundColor: '#f3e8ff',
    borderRadius: 8
  },
  buttonText: {
    fontSize: 16,
    color: '#6b21a8'
  }
});

The state variable stores whether the item is a favorite. Pressing the button reverses the value and updates the label. In a real application, persistent favorites may also need to be saved to an API or local storage.

21. Creating a Loading Button

When a user submits a form or starts a network request, the application should provide feedback that the action is in progress. A loading button can prevent repeated submissions and communicate the current state.

import React, { useState } from 'react';
import {
  View,
  Text,
  Pressable,
  ActivityIndicator,
  StyleSheet
} from 'react-native';

export default function LoadingButton() {
  const [loading, setLoading] = useState(false);

  const handleSubmit = async () => {
    if (loading) return;

    setLoading(true);

    try {
      await new Promise(resolve => setTimeout(resolve, 1500));
      console.log('Operation completed');
    } catch (error) {
      console.error('Operation failed', error);
    } finally {
      setLoading(false);
    }
  };

  return (
    <View style={styles.container}>
      <Pressable
        onPress={handleSubmit}
        disabled={loading}
        accessibilityRole="button"
        accessibilityState={{ disabled: loading, busy: loading }}
        style={({ pressed }) => [
          styles.button,
          pressed && !loading && styles.pressed,
          loading && styles.disabled
        ]}
      >
        {loading ? (
          <View style={styles.row}>
            <ActivityIndicator color="#ffffff" />
            <Text style={styles.buttonText}>Please wait...</Text>
          </View>
        ) : (
          <Text style={styles.buttonText}>Submit</Text>
        )}
      </Pressable>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    padding: 20
  },
  button: {
    padding: 16,
    borderRadius: 8,
    alignItems: 'center',
    backgroundColor: '#2563eb'
  },
  pressed: {
    backgroundColor: '#1d4ed8'
  },
  disabled: {
    backgroundColor: '#93a3b8'
  },
  row: {
    flexDirection: 'row',
    alignItems: 'center',
    gap: 10
  },
  buttonText: {
    color: '#ffffff',
    fontSize: 16,
    fontWeight: 'bold'
  }
});

The timeout in this example simulates an asynchronous operation for demonstration purposes. Replace it with your actual API request or business logic. The finally block resets the loading state whether the operation succeeds or fails.

22. Handling Form Submission with Pressable

Form submission is a common use case for interactive components. A button can validate user input before performing an action.

import React, { useState } from 'react';
import {
  View,
  Text,
  TextInput,
  Pressable,
  Alert,
  StyleSheet
} from 'react-native';

export default function LoginForm() {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');

  const handleLogin = () => {
    if (!email.trim() || !password) {
      Alert.alert('Validation Error', 'Enter your email and password.');
      return;
    }

    Alert.alert('Login', 'Input validation passed.');
  };

  return (
    <View style={styles.container}>
      <Text style={styles.heading}>Login</Text>

      <TextInput
        value={email}
        onChangeText={setEmail}
        placeholder="Email address"
        keyboardType="email-address"
        autoCapitalize="none"
        style={styles.input}
      />

      <TextInput
        value={password}
        onChangeText={setPassword}
        placeholder="Password"
        secureTextEntry
        style={styles.input}
      />

      <Pressable style={styles.button} onPress={handleLogin}>
        <Text style={styles.buttonText}>Login</Text>
      </Pressable>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
    justifyContent: 'center'
  },
  heading: {
    fontSize: 28,
    fontWeight: 'bold',
    marginBottom: 20
  },
  input: {
    borderWidth: 1,
    borderColor: '#cccccc',
    padding: 12,
    borderRadius: 8,
    marginBottom: 14
  },
  button: {
    backgroundColor: '#2563eb',
    padding: 15,
    alignItems: 'center',
    borderRadius: 8
  },
  buttonText: {
    color: '#ffffff',
    fontWeight: 'bold'
  }
});

This example checks whether the fields are empty. Real authentication should also validate input appropriately and send credentials securely to a backend service. Never treat client-side validation alone as sufficient security.

23. Accessibility for Interactive Components

Accessibility ensures that interactive elements can be understood and used by people with different abilities. Buttons should have a clear purpose, an accessible name, and a state that can be communicated to accessibility services.

Useful Accessibility Props

  • accessibilityRole="button" identifies the element as a button.
  • accessibilityLabel describes the action or purpose of the element.
  • accessibilityHint can explain what happens when the element is activated.
  • accessibilityState can communicate states such as disabled or busy where supported.
  • disabled prevents the component's normal press action when unavailable.

Example

<Pressable
  accessibilityRole="button"
  accessibilityLabel="Save profile"
  accessibilityHint="Saves the changes to your profile"
  accessibilityState={{ disabled: false }}
  onPress={handleSave}
>
  <Text>Save</Text>
</Pressable>

Accessibility Best Practices

  • Use descriptive labels rather than vague labels such as "Click here".
  • Ensure the text is readable and has sufficient contrast.
  • Provide feedback when an action succeeds or fails.
  • Make the touch target large enough to be comfortably activated.
  • Communicate disabled and busy states where appropriate.
  • Test interactive elements with screen readers and on physical devices.

24. Common Mistakes and Troubleshooting

Problem Possible Cause Solution
Button action runs immediately. The handler is called during rendering. Pass a function reference, such as onPress={handlePress}.
Pressable does not look like a button. Pressable does not supply a complete default button design. Add padding, background color, border radius, and text styling.
Button cannot be pressed. It may be disabled or covered by another element. Check the disabled prop, layout, and overlapping components.
TouchableHighlight shows an unexpected color. The underlay color conflicts with the child styling. Adjust underlayColor and the child's background.
TouchableOpacity looks too transparent. The activeOpacity value is too low. Increase activeOpacity to provide subtler feedback.
Long press does not trigger. The press duration is too short or the gesture is cancelled. Check onLongPress, delayLongPress, and touch handling.
Button can be submitted repeatedly. The action is not disabled while a request is running. Use loading state and disable the component during submission.
Button text is difficult to read. Insufficient contrast or unsuitable text styling. Adjust the foreground and background colors.
Accessibility tools announce an unclear action. The element has no meaningful accessible name. Add a descriptive accessibilityLabel and role.

25. Best Practices for Using Touch Components

  • Prefer Pressable for new custom interactive components that require flexible styling.
  • Use Button for simple actions when its platform-rendered appearance is suitable.
  • Choose TouchableOpacity or TouchableHighlight when their feedback styles fit the interface.
  • Avoid TouchableWithoutFeedback for ordinary buttons unless the lack of feedback is intentional.
  • Use clear event handler names, such as handleSubmit and handleSave.
  • Keep touch handlers focused on one responsibility.
  • Disable buttons when actions are unavailable or already being processed.
  • Show loading feedback for asynchronous operations.
  • Use accessible labels and roles for interactive controls.
  • Provide visible feedback for successful, failed, and unavailable actions.
  • Test touch interactions on both Android and iOS.
  • Prevent duplicate requests when a user taps repeatedly.
  • Use reusable components to maintain consistent button design.

26. Practical Project: Interactive Action Menu

Project Objective: Create an action menu with custom Pressable buttons for viewing a profile, saving settings, and logging out.

Requirements

  • Use Pressable to create custom buttons.
  • Display a label for each action.
  • Provide visual feedback when buttons are pressed.
  • Use separate event handlers for each action.
  • Include accessible button labels.

Complete Project Code

import React from 'react';
import {
  View,
  Text,
  Pressable,
  Alert,
  StyleSheet
} from 'react-native';

export default function ActionMenu() {
  const handleProfile = () => {
    Alert.alert('Profile', 'Profile selected.');
  };

  const handleSettings = () => {
    Alert.alert('Settings', 'Settings selected.');
  };

  const handleLogout = () => {
    Alert.alert('Logout', 'Logout selected.');
  };

  return (
    <View style={styles.container}>
      <Text style={styles.heading}>Account Menu</Text>

      <Pressable
        style={({ pressed }) => [
          styles.button,
          pressed && styles.pressed
        ]}
        onPress={handleProfile}
        accessibilityRole="button"
        accessibilityLabel="View profile"
      >
        <Text style={styles.buttonText}>View Profile</Text>
      </Pressable>

      <Pressable
        style={({ pressed }) => [
          styles.button,
          pressed && styles.pressed
        ]}
        onPress={handleSettings}
        accessibilityRole="button"
        accessibilityLabel="Open settings"
      >
        <Text style={styles.buttonText}>Settings</Text>
      </Pressable>

      <Pressable
        style={({ pressed }) => [
          styles.logoutButton,
          pressed && styles.logoutPressed
        ]}
        onPress={handleLogout}
        accessibilityRole="button"
        accessibilityLabel="Log out"
      >
        <Text style={styles.buttonText}>Logout</Text>
      </Pressable>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    padding: 24,
    backgroundColor: '#f8fafc'
  },
  heading: {
    fontSize: 26,
    fontWeight: 'bold',
    marginBottom: 24,
    textAlign: 'center'
  },
  button: {
    backgroundColor: '#2563eb',
    padding: 16,
    borderRadius: 10,
    alignItems: 'center',
    marginBottom: 14
  },
  pressed: {
    backgroundColor: '#1d4ed8'
  },
  logoutButton: {
    backgroundColor: '#dc2626',
    padding: 16,
    borderRadius: 10,
    alignItems: 'center'
  },
  logoutPressed: {
    backgroundColor: '#991b1b'
  },
  buttonText: {
    color: '#ffffff',
    fontSize: 16,
    fontWeight: 'bold'
  }
});

Project Explanation

  1. View: Organizes the action menu layout.
  2. Text: Displays the heading and button labels.
  3. Pressable: Makes each action respond to user input.
  4. onPress: Connects each button to its corresponding handler.
  5. Dynamic style: Changes the button's background while it is pressed.
  6. Accessibility: Gives each button a meaningful role and label.

The example uses alerts to demonstrate interaction. In a production application, replace these handlers with navigation, settings updates, and a properly implemented logout workflow.

27. Practice Exercises

Beginner Exercises

  1. Create a Button that displays an alert when pressed.
  2. Create a custom Pressable button with a background color and rounded corners.
  3. Use TouchableOpacity to create a button with opacity feedback.
  4. Use TouchableHighlight with a custom underlay color.
  5. Create a disabled button and give it a different appearance.

Intermediate Exercises

  1. Build a counter using Pressable and useState.
  2. Create a favorite button that toggles between selected and unselected states.
  3. Implement a long-press action using Pressable.
  4. Build a reusable CustomButton component with title and onPress props.
  5. Create a loading button that prevents repeated submissions.

Advanced Exercises

  1. Build a login form with validation and a disabled submit button.
  2. Create a reusable button component with primary, secondary, and danger variants.
  3. Implement a custom pressed-state animation.
  4. Build an accessible action menu with different actions.
  5. Test touch interactions on Android and iOS and document any differences.

28. Interview Questions and Answers

Q1. What is Pressable in React Native?

Answer: Pressable is a built-in component that makes its children respond to touch interactions. It supports press callbacks, dynamic styling, long-press behavior, and other interaction options.

Q2. What is the Button component?

Answer: Button is a built-in component for creating simple platform-rendered buttons. It mainly uses the title and onPress props, with limited styling customization.

Q3. What is TouchableOpacity?

Answer: TouchableOpacity provides touch feedback by reducing the opacity of its children while they are pressed.

Q4. What is TouchableHighlight?

Answer: TouchableHighlight displays an underlay color during a press. It is useful when the desired feedback is a highlighted or darkened background.

Q5. What is TouchableWithoutFeedback?

Answer: TouchableWithoutFeedback detects touch interactions without providing its own visual press feedback. It should be used selectively.

Q6. What is the difference between Pressable and TouchableOpacity?

Answer: Pressable offers flexible press-state styling and several interaction callbacks. TouchableOpacity provides a simpler opacity-based feedback effect.

Q7. What is onPress?

Answer: onPress is a callback that runs when a press interaction is successfully recognized.

Q8. What is onLongPress?

Answer: onLongPress is a callback triggered when a user presses and holds an element long enough for the long-press gesture to be recognized.

Q9. What is the purpose of onPressIn?

Answer: onPressIn runs when the press interaction begins. It can be used to trigger early feedback or record the start of an interaction.

Q10. What is the purpose of onPressOut?

Answer: onPressOut runs when the press interaction ends, including situations where the interaction is cancelled.

Q11. How do you disable a Pressable component?

Answer: Set disabled={true}. A custom disabled style can also be applied to make the unavailable state visible.

Q12. How do you change a Pressable button's style when it is pressed?

Answer: Pass a function to the style prop and use its pressed state to return conditional styles.

Q13. Why create a reusable button component?

Answer: Reusable components reduce duplicated code, improve consistency, and make it easier to maintain button styling and behavior throughout an application.

Q14. How can you prevent multiple form submissions?

Answer: Track the loading state, disable the button while the request is running, and guard the event handler against duplicate calls.

Q15. Which component is suitable for a custom button?

Answer: Pressable is generally a good choice for a custom button because it supports flexible styling, press states, and interaction callbacks.

29. Quick Revision Checklist

  • Understand the role of Pressable, Button, and Touchable components.
  • Use onPress to handle a completed press.
  • Use onPressIn and onPressOut to track press interactions.
  • Use onLongPress to detect press-and-hold interactions.
  • Use dynamic styles to provide pressed-state feedback.
  • Use Button for simple actions with minimal customization.
  • Use TouchableOpacity for opacity-based feedback.
  • Use TouchableHighlight for underlay-based feedback.
  • Use TouchableWithoutFeedback only when the lack of visual feedback is intentional.
  • Use disabled and loading states to prevent unavailable or repeated actions.
  • Create reusable button components for consistent design.
  • Provide meaningful accessibility roles and labels.
  • Test touch behavior on Android and iOS.

30. Conclusion

Pressable, Button, and Touchable components help developers build interactive React Native applications. Button is appropriate for simple actions, Pressable is flexible for custom controls, and Touchable components provide specific feedback styles such as opacity changes and underlay highlighting.

By understanding their props, event callbacks, disabled states, accessibility features, and styling options, developers can create reliable buttons, form actions, menus, counters, and reusable interface components.

Practice these concepts by creating a custom button library and using it in a login form, product list, and account menu. For further learning, visit the React Native Training course at JustAcademy or register for a course demo.

31. Additional Learning Resources

whatsapp